import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable, Logger, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Cache } from 'cache-manager';
import { Repository } from 'typeorm';
import { CACHE_KEYS, CACHE_TTL } from '../config/cache.config';
import { CreateHotelDto, UpdateHotelDto } from '../dto/hotel.dto';
import { Hotel } from '../entities/hotel.entity';

@Injectable()
export class HotelsService {
  private readonly logger = new Logger(HotelsService.name);
  private readonly mockHotels: Hotel[] = [
    {
      hotelID: 1,
      name: '香格里拉酒店',
      address: '北京市朝阳区建国门外大街1号',
      starRating: 5,
      rooms: [],
    },
    {
      hotelID: 2,
      name: '希尔顿酒店',
      address: '上海市浦东新区世纪大道200号',
      starRating: 5,
      rooms: [],
    },
    {
      hotelID: 3,
      name: '万豪酒店',
      address: '广州市天河区珠江新城冼村路12号',
      starRating: 4,
      rooms: [],
    },
  ];

  constructor(
    @InjectRepository(Hotel)
    private hotelsRepository: Repository<Hotel>,
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
  ) {
    // 初始化时添加模拟数据
    this.seedMockData();
  }

  private async seedMockData() {
    const count = await this.hotelsRepository.count();
    if (count === 0) {
      await Promise.all(
        this.mockHotels.map((hotel) =>
          this.hotelsRepository.save(this.hotelsRepository.create(hotel)),
        ),
      );
    }
  }

  async findAll(): Promise<Hotel[]> {
    try {
      // 尝试从缓存获取酒店列表
      const cachedHotels = await this.cacheManager.get<Hotel[]>(
        CACHE_KEYS.HOTELS_LIST,
      );

      if (cachedHotels) {
        this.logger.log('返回缓存的酒店列表数据');
        return cachedHotels;
      }

      // 缓存未命中，从数据库获取
      this.logger.log('从数据库获取酒店列表');
      const hotels = await this.hotelsRepository.find();

      // 保存到缓存
      await this.cacheManager.set(
        CACHE_KEYS.HOTELS_LIST,
        hotels,
        CACHE_TTL.HOTELS_LIST,
      );

      return hotels;
    } catch (error: unknown) {
      const err = error as Error;
      this.logger.error(`获取酒店列表失败: ${err.message}`, err.stack);
      // 发生错误时，直接从数据库获取
      return this.hotelsRepository.find();
    }
  }

  async findOne(id: number): Promise<Hotel> {
    try {
      // 尝试从缓存获取酒店详情
      const cacheKey = `${CACHE_KEYS.HOTEL_DETAIL}${id}`;
      const cachedHotel = await this.cacheManager.get<Hotel>(cacheKey);

      if (cachedHotel) {
        this.logger.log(`返回缓存的酒店ID=${id}详情数据`);
        return cachedHotel;
      }

      // 缓存未命中，从数据库获取
      this.logger.log(`从数据库获取酒店ID=${id}详情`);
      const hotel = await this.hotelsRepository.findOne({
        where: { hotelID: id },
        relations: ['rooms'],
      });

      if (!hotel) {
        throw new NotFoundException(`未找到ID为${id}的酒店`);
      }

      // 保存到缓存
      await this.cacheManager.set(cacheKey, hotel, CACHE_TTL.HOTEL_DETAIL);

      return hotel;
    } catch (error: unknown) {
      if (error instanceof NotFoundException) {
        throw error;
      }

      const err = error as Error;
      this.logger.error(`获取酒店详情失败: ${err.message}`, err.stack);
      // 发生错误时，直接从数据库获取
      const hotel = await this.hotelsRepository.findOne({
        where: { hotelID: id },
        relations: ['rooms'],
      });

      if (!hotel) {
        throw new NotFoundException(`未找到ID为${id}的酒店`);
      }

      return hotel;
    }
  }

  async findHotelRooms(id: number) {
    const hotel = await this.findOne(id);
    return hotel.rooms;
  }

  async create(createHotelDto: CreateHotelDto): Promise<Hotel> {
    try {
      const hotel = this.hotelsRepository.create(createHotelDto);
      const savedHotel = await this.hotelsRepository.save(hotel);

      // 清除酒店列表缓存
      await this.cacheManager.del(CACHE_KEYS.HOTELS_LIST);

      return savedHotel;
    } catch (error: unknown) {
      const err = error as Error;
      this.logger.error(`创建酒店失败: ${err.message}`, err.stack);
      throw error;
    }
  }

  async update(id: number, updateHotelDto: UpdateHotelDto): Promise<Hotel> {
    try {
      await this.hotelsRepository.update(id, updateHotelDto);

      // 清除相关缓存
      await this.cacheManager.del(CACHE_KEYS.HOTELS_LIST);
      await this.cacheManager.del(`${CACHE_KEYS.HOTEL_DETAIL}${id}`);

      return this.findOne(id);
    } catch (error: unknown) {
      const err = error as Error;
      this.logger.error(`更新酒店失败: ${err.message}`, err.stack);
      throw error;
    }
  }

  async remove(id: number): Promise<void> {
    try {
      await this.hotelsRepository.delete(id);

      // 清除相关缓存
      await this.cacheManager.del(CACHE_KEYS.HOTELS_LIST);
      await this.cacheManager.del(`${CACHE_KEYS.HOTEL_DETAIL}${id}`);
    } catch (error: unknown) {
      const err = error as Error;
      this.logger.error(`删除酒店失败: ${err.message}`, err.stack);
      throw error;
    }
  }
}
